#include "varDict.h"
using namespace sge;

ScriptServer* VarDict::scriptServer = 0;

VarDict::VarDict() {
}

VarDict::VarDict(PythonObject dict) {
    fromPythonDict(dict);
}

Var& VarDict::getVar(const String& varName) const {
    if (hasVar(varName))
        return ((VarDict*)this)->vars[varName];
    else {
        Var var;
        ((VarDict*)this)->vars[varName] = var;
        return ((VarDict*)this)->vars[varName];
    }
}

bool VarDict::hasVar(const String& varName) const {
    return vars.find(varName) != vars.end();
}

bool VarDict::getB(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getB();
}

void VarDict::setB(const String& varName, bool b) {
    getVar(varName).setB(b);
    onSetVar(varName);
}

void VarDict::defaultB(const String& varName, bool b) {
    if (!hasVar(varName))
        getVar(varName).setB(b);
}

int VarDict::getI(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getI();
}

void VarDict::setI(const String& varName, int i) {
    getVar(varName).setI(i);
    onSetVar(varName);
}

void VarDict::defaultI(const String& varName, int i) {
    if (!hasVar(varName))
        getVar(varName).setI(i);
}

float VarDict::getF(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getF();
}

void VarDict::setF(const String& varName, float f) {
    getVar(varName).setF(f);
    onSetVar(varName);
}

void VarDict::defaultF(const String& varName, float f) {
    if (!hasVar(varName))
        getVar(varName).setF(f);
}

String VarDict::getS(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getS();
}

void VarDict::setS(const String& varName, String s) {
    getVar(varName).setS(s);
    onSetVar(varName);
}

void VarDict::defaultS(const String& varName, String s) {
    if (!hasVar(varName))
        getVar(varName).setS(s);
}

Vector3 VarDict::getV(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getV();
}

void VarDict::setV(const String& varName, Vector3 v) {
    getVar(varName).setV(v);
    onSetVar(varName);
}

void VarDict::defaultV(const String& varName, Vector3 v) {
    if (!hasVar(varName))
        getVar(varName).setV(v);
}

Quaternion VarDict::getQ(const String& varName) const {
    onGetVar(varName);
    return getVar(varName).getQ();
}

void VarDict::setQ(const String& varName, Quaternion q) {
    getVar(varName).setQ(q);
    onSetVar(varName);
}

void VarDict::defaultQ(const String& varName, Quaternion q) {
    if (!hasVar(varName))
        getVar(varName).setQ(q);
}

StringList VarDict::getVarNames() {
    StringList names;
    for (StringVarMap::iterator i = vars.begin(); i != vars.end(); ++i)
        names.push_back(i->first);
    return names;
}

bool VarDict::getVarDirty(const String& varName) const {
    return getVar(varName).getDirty();
}

void VarDict::setVarDirty(const String& varName, bool _dirty) {
    getVar(varName).setDirty(_dirty);
}

void VarDict::pySetVar(const String& varName, PythonObject val) {
    String type = scriptServer->getType(val);
    if (type == "bool")
        setB(varName,boost::python::extract<bool>(val));
    else if (type == "int")
        setI(varName,boost::python::extract<int>(val));
    else if (type == "float")
        setF(varName,boost::python::extract<float>(val));
    else if (type == "str")
        setS(varName,boost::python::extract<String>(val));
}

void VarDict::pyDefaultVar(const String& varName, PythonObject val) {
    if (!hasVar(varName))
        pySetVar(varName,val);
}

PythonObject VarDict::pyGetVar(const String& varName) const {
    if (hasVar(varName)) {
        VarType type = getVar(varName).getVarType();
        if (type == BOOL)
            return PythonObject(getB(varName));
        else if (type == INT)
            return PythonObject(getI(varName));
        else if (type == FLOAT)
            return PythonObject(getF(varName));
        else if (type == STRING)
            return PythonObject(getS(varName));
        else
            return PythonObject();
    } else
        return PythonObject();
}

void VarDict::fromPythonDict(PythonObject dict) {
    PythonObject items = dict.attr("items")();
    int len = scriptServer->getLength(items), i;
    for (i = 0; i < len; ++i)
        pySetVar(boost::python::extract<String>(items[i][0]),items[i][1]);
}

PythonObject VarDict::toPythonDict() const {
    boost::python::dict dict;
    for (StringVarMap::iterator i = ((VarDict*)this)->vars.begin(); i != ((VarDict*)this)->vars.end(); ++i)
        dict[i->first] = pyGetVar(i->first);
    return dict;
}

PythonObject VarDict::pyGetVarNames() {
    boost::python::list varNames;
    for (StringVarMap::iterator i = vars.begin(); i != vars.end(); ++i)
        varNames.append(i->first);
    return varNames;
}

void VarDict::registerPythonBindings() {
    boost::python::class_<VarDict>("VarDict",boost::python::init<>())
        .def(boost::python::init<boost::python::dict>())
        .def("setVar",&VarDict::pySetVar)
        .def("getVar",&VarDict::pyGetVar)
        .def("defaultVar",&VarDict::pyDefaultVar)
        .def("getVarNames",&VarDict::pyGetVarNames)
        .def("getVarDirty",&VarDict::getVarDirty)
        .def("setVarDirty",&VarDict::setVarDirty)
        .def("toPythonDict",&VarDict::toPythonDict)
        .def("fromPythonDict",&VarDict::fromPythonDict)
    ;
}
